package cn.wolfcode.web.controller;

import cn.wolfcode.common.domain.UserInfo;
import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.CommonCodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.common.web.anno.RequireLogin;
import cn.wolfcode.domain.OrderInfo;
import cn.wolfcode.domain.SeckillProductVo;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMessage;
import cn.wolfcode.redis.CommonRedisKey;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import com.sun.org.apache.bcel.internal.generic.NEW;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.ConcurrentHashMap;


@RestController
@RequestMapping("/order")
@Slf4j
public class OrderInfoController {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private IOrderInfoService orderInfoService;

    //本地标识
    public static final ConcurrentHashMap<Long, Boolean> LOCAL_FLAG = new ConcurrentHashMap<>();


    @RequireLogin
    @PostMapping("/doSeckill")
    public Result<String> doSeckill(Integer time, Long seckillId, @RequestHeader("token") String token) {
        if (StringUtils.isEmpty(time) || StringUtils.isEmpty(seckillId)) {
            throw new BusinessException(CommonCodeMsg.PARAM_IS_EMPTY);
        }
        //1 判断是否是用户误点击 1/分钟(分布式锁)
        String key = CommonRedisKey.USER_TOKEN.getRealKey(token);
        UserInfo userInfo = JSON.parseObject(redisTemplate.opsForValue().get(key), UserInfo.class);
        //setNx()   key=uid+secId,  value=1   value值随便写，啥都行
        key = SeckillRedisKey.SECKILL_UID_SECID_VALUE.getRealKey(userInfo.getPhone() + ":" + seckillId);
        if (!redisTemplate.opsForValue().setIfAbsent(key, "1",
                SeckillRedisKey.SECKILL_UID_SECID_VALUE.getExpireTime(),
                SeckillRedisKey.SECKILL_UID_SECID_VALUE.getUnit())) {
            //重复点击
            throw new BusinessException(SeckillCodeMsg.USER_CLICK_REPEAT);
        }
        //2 判断本地标识是否为true
        if (StringUtils.isEmpty(LOCAL_FLAG.get(seckillId))) {
            LOCAL_FLAG.put(seckillId, true);
        } else if (!LOCAL_FLAG.get(seckillId)) {
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        //3 判断是否是重复订单  set类型    key=phone    value=seckillId
        key = SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(userInfo.getPhone().toString());
        //value是String类型，不改容易出问题
        if (redisTemplate.opsForSet().isMember(key, seckillId.toString())) {
            throw new BusinessException(SeckillCodeMsg.REPEAT_SECKILL);
        }

        //4 判断预库存是否为零(本地标识改为false)
        key = SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(time.toString());
        String smallKey = seckillId.toString();
        String s = (String) redisTemplate.opsForHash().get(key, smallKey);
        if (Integer.parseInt(s) <= 0) {
            LOCAL_FLAG.put(seckillId, false);
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }

        //1 redis预库存-1(单线程),判断值是否>0,
        //        如果不是,本地标识设置为false
        if (redisTemplate.opsForHash().increment(key, smallKey, -1L)<=0) {
            LOCAL_FLAG.put(seckillId, false);
        }

        //2 发mq同步消息
        OrderMessage msg = new OrderMessage();
        msg.setTime(time);
        msg.setSeckillId(seckillId);
        msg.setToken(token);
        msg.setUserPhone(userInfo.getPhone());
        SendResult sendResult = rocketMQTemplate.syncSend(MQConstant.ORDER_PEDDING_TOPIC, msg);

        if (sendResult.getSendStatus()== SendStatus.SEND_OK) {
            return Result.success("排队成功");
        }
        //        mq发送失败
        //1 redis预库存+1
        redisTemplate.opsForHash().increment(key, smallKey, 1L);
        //2 发广播消息,本地标识设置为true
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC, seckillId.toString());
        throw new BusinessException(SeckillCodeMsg.SECKILL_ERROR);

    }

    @GetMapping("/find")
    @RequireLogin
    public Result<OrderInfo> find(String orderNo) {
        if (StringUtils.isEmpty(orderNo)) {
            throw new BusinessException(CommonCodeMsg.PARAM_IS_EMPTY);
        }
        OrderInfo orderInfo = orderInfoService.find(orderNo);
        return Result.success(orderInfo);
    }
}
